package cn.topcodes.tcsf.admin.service.impl;

import cn.topcodes.tcsf.admin.commons.domain.ValueRangeConstant;
import cn.topcodes.tcsf.admin.commons.generic.GenericService;
import cn.topcodes.tcsf.admin.domain.entity.SysMenuPermRela;
import cn.topcodes.tcsf.admin.domain.entity.SysPerm;
import cn.topcodes.tcsf.admin.domain.entity.SysRolePermRela;
import cn.topcodes.tcsf.admin.domain.entity.SysUrlPermRela;
import cn.topcodes.tcsf.admin.domain.form.NestableSort;
import cn.topcodes.tcsf.admin.domain.view.SysPermVo;
import cn.topcodes.tcsf.admin.mapper.SysMenuPermRelaMapper;
import cn.topcodes.tcsf.admin.mapper.SysRolePermRelaMapper;
import cn.topcodes.tcsf.admin.mapper.SysUrlPermRelaMapper;
import cn.topcodes.tcsf.admin.service.org.SysRoleService;
import cn.topcodes.tcsf.admin.service.res.SysPermService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

@Service
@Transactional(readOnly=true)
public class SysPermServiceImpl extends GenericService<SysPerm> implements SysPermService {

    @Autowired
    private SysRolePermRelaMapper sysRolePermRelaMapper;

    @Autowired
    private SysMenuPermRelaMapper sysMenuPermRelaMapper;

    @Autowired
    private SysUrlPermRelaMapper sysUrlPermRelaMapper;

    @Autowired
    private SysRoleService sysRoleService;

    @Override
    public List<SysPerm> getRootPerms() {
        Example example = this.buildExample();
        example.or().andIsNull("parentId");
        return this.findAll(example);
    }

    @Override
    public List<SysPermVo> getPerms(Long assignRoleId, Long id, Long curUserId) {
        Example example = this.buildExample();
        example.or().andIsNull("parentId");
        List<SysPerm> list = this.findAll(example);
        Collections.sort(list);
        List<SysPermVo> vos = new ArrayList<>();
        for(SysPerm perm : list) {
            SysPermVo vo = new SysPermVo();
            vo.setId(perm.getId());
            vo.setName(perm.getName());
            vo.setDescription(perm.getDescription());
            vo.setIsBind(isPermitted(id,perm.getId()));
            Example example1 = this.buildExample();
            example1.or().andEqualTo("parentId",perm.getId());
            List<SysPerm> childs = this.findAll(example1);
            Collections.sort(childs);
            List<SysPermVo> childVos = new ArrayList<>();
            for(SysPerm child : childs) {
                SysPermVo childVo = new SysPermVo();
                childVo.setId(child.getId());
                childVo.setDescription(child.getDescription());
                childVo.setIsBind(isPermitted(id,child.getId()));
                childVo.setName(child.getName());
                /*若非开发者角色，将只取出有权限的进行展示*/
                if(sysRoleService.hasRole(curUserId, ValueRangeConstant.BuiltInRole.ROLE_DEVELOPER) || isPermitted(assignRoleId,perm.getId())) {
                    childVos.add(childVo);
                }
            }
            vo.setChildrens(childVos);
            //  子权限全无权限访问，则没有必要显示权限分类
            if(!childVos.isEmpty()) {
                vos.add(vo);
            }
        }
        return vos;
    }

    @Override
    @Transactional(readOnly = false)
    public void create(SysPerm perm, Long[] menus, Long[] urls) {
        Long id = this.create(perm);
        if(menus != null) {
            for (Long menuId : menus) {
                SysMenuPermRela mpr = new SysMenuPermRela();
                mpr.setCreatedTime(new Date());
                mpr.setUpdatedTime(new Date());
                mpr.setDataState(ValueRangeConstant.DataState.DATA_STATE_ENABLE);
                mpr.setMenuId(menuId);
                mpr.setPermId(id);
                sysMenuPermRelaMapper.insert(mpr);
            }
        }
        if(urls != null) {
            for (Long urlId : urls) {
                SysUrlPermRela upr = new SysUrlPermRela();
                upr.setCreatedTime(new Date());
                upr.setUpdatedTime(new Date());
                upr.setDataState(ValueRangeConstant.DataState.DATA_STATE_ENABLE);
                upr.setUrlId(urlId);
                upr.setPermId(id);
                sysUrlPermRelaMapper.insert(upr);
            }
        }
    }

    @Override
    @Transactional(readOnly = false)
    public void update(SysPerm perm, Long[] menus, Long[] urls) {
        SysPerm entity = this.findOne(perm.getId());
        perm.setParentId(entity.getParentId());
        perm.setSort(entity.getSort());
        this.update(perm);
        Example example = new Example(SysMenuPermRela.class);
        example.or().andEqualTo("permId",perm.getId());
        this.sysMenuPermRelaMapper.deleteByExample(example);
        if(menus != null) {
            for (Long menuId : menus) {
                SysMenuPermRela mpr = new SysMenuPermRela();
                mpr.setCreatedTime(new Date());
                mpr.setUpdatedTime(new Date());
                mpr.setDataState(ValueRangeConstant.DataState.DATA_STATE_ENABLE);
                mpr.setMenuId(menuId);
                mpr.setPermId(perm.getId());
                sysMenuPermRelaMapper.insert(mpr);
            }
        }
        example = new Example(SysUrlPermRela.class);
        example.or().andEqualTo("permId",perm.getId());
        this.sysUrlPermRelaMapper.deleteByExample(example);
        if(urls != null) {
            for (Long urlId : urls) {
                SysUrlPermRela upr = new SysUrlPermRela();
                upr.setCreatedTime(new Date());
                upr.setUpdatedTime(new Date());
                upr.setDataState(ValueRangeConstant.DataState.DATA_STATE_ENABLE);
                upr.setUrlId(urlId);
                upr.setPermId(perm.getId());
                sysUrlPermRelaMapper.insert(upr);
            }
        }
    }

    @Override
    public Long[] getMenus(Long permId) {
        Example example = new Example(SysMenuPermRela.class);
        example.or().andEqualTo("permId",permId);
        List<SysMenuPermRela> list = this.sysMenuPermRelaMapper.selectByExample(example);
        Long[] menuIds = new Long[list.size()];
        for(int i = 0 ; i < list.size() ; i ++ ) {
            menuIds[i] = list.get(i).getMenuId();
        }
        return menuIds;
    }

    @Override
    public Long[] getUrls(Long permId) {
        Example example = new Example(SysUrlPermRela.class);
        example.or().andEqualTo("permId",permId);
        List<SysUrlPermRela> list = this.sysUrlPermRelaMapper.selectByExample(example);
        Long[] urlIds = new Long[list.size()];
        for(int i = 0 ; i < list.size() ; i ++ ) {
            urlIds[i] = list.get(i).getUrlId();
        }
        return urlIds;
    }

    @Override
    @Transactional(readOnly = false)
    public void saveSort(List<NestableSort> sort) {
        tranSaveSort(sort,null);
    }

    @Transactional(readOnly = false)
    private void tranSaveSort(List<NestableSort> sort,Long parentId) {
        if(sort == null) return;
        for(int i = 0 ; i < sort.size() ; i ++ ) {
            NestableSort s = sort.get(i);
            SysPerm perm = this.findOne(s.getId());
            perm.setSort(i);
            perm.setParentId(parentId);
            this.update(perm);
            tranSaveSort(s.getChildren(),s.getId());
        }
    }

    public boolean isPermitted(Long roleId, Long permId) {
        Example example = new Example(SysRolePermRela.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("roleId",roleId);
        criteria.andEqualTo("permId",permId);
        int count = this.sysRolePermRelaMapper.selectCountByExample(example);
        return count > 0;
    }
}
